#ifndef __case_parses_kenny_kfjiweur89u83r33e3e__
#define __case_parses_kenny_kfjiweur89u83r33e3e__

#include <thread>

#include <hude/base/log.hpp>
#include <hude/base/hex.hpp>
#include <hude/utils/parses.hpp>

#include "test/test.hpp"

namespace test
{
    using namespace hude;

    //--------------------------------------------------------------------------------
    struct case_parses_t : public hude::test::case_t
    {
        enum : size_t { emCOUNT = 1U * 100U, emINTERVAL = 0U, emTIMEOUT = 1000U };

        //声明解析栈类型
        using parses_t = utils::parses_t< byte_t >;

        //为测试构造一个循环数据管道
        struct loop_t
        {
            parses_t  parses_;

            bool operator()( const parses_t::buffer_t& buffer )
            {
                static byte_t content[] = { 0xaa, 0xbb, 0xcc, 0x02, 0U, 0U, 0U, 0U, 0x12, 0x34 };

                for( size_t i = 0; i < 1000U; ++i )
                {
                    auto ptr = parses_.buffer_alloc( content, content + 8U );
                    parses_.buffer_push( ptr );
                }

                auto ptr = parses_.buffer_alloc();
                *ptr = buffer;
                parses_.buffer_push( ptr );

                return true;
            }
        };

        // 声明同步请求类型, 同步请求对象属于解析栈的订阅者
        using observe_t = utils::sync_observe_t< loop_t, parses_t >; 

        // 测试过程
        bool run() override
        {
            const size_t lenght = 8U;

            size_t ret = 0, dop = 0, to = 0;

            // 循环数据管道对象
            loop_t loop;

            // 解析栈工作线程
            auto th_ = std::thread{ [&loop, &dop]()
            {
                // 桢查找器, 从祼数据中扫描一个桢结构的方法
                auto finder = []( parses_t::citr_t& b, parses_t::citr_t& e ) -> parses_t::citr_t
                {
                    while( b != e )
                    {
                        // 逐个比较桢头首字节
                        if( *b == 0xaa )
                        {
                            // 如果数据长度不足
                            if( size_t(e - b) < lenght )
                            {
                                return e;
                            }

                            const byte_t* h = &(*b);

                            // 对比其它桢头字节
                            if( h[1] == 0xbb && h[2] == 0xcc )
                            {
                                parses_t::citr_t r = b;

                                b += lenght;

                                return r;
                            }
                        }

                        ++b;
                    }

                    return ( b = e );
                };

                // 无效数据丢弃事件
                auto drop = [&dop]( parses_t::citr_t b, parses_t::citr_t e ) -> void
                {
                    dop += e - b;

                    log_war( "droped bytes: %u(%s)", e - b, hude::utils::to_hex( &(*b), e - b ).c_str() );
                };

                // 开始解析栈循环
                loop.parses_.process( finder, drop );
            } };

            // 一次同步请求
            auto request = [&ret, &to]( size_t index, loop_t& loop, const parses_t::buffer_t& buffer )
            {
                // 声明请求对象，请求对象是一次性的，不可重用。
                observe_t observe{ &loop, &loop.parses_ };

                // 请求回应的桢处理回调
                auto on_reply = [index]( parses_t::citr_t b, parses_t::citr_t e ) -> observe_t::result_t
                {
                    auto h = (const uint8_t*)&(*(b + 3));
                    auto p = (const uint32_t*)&(*(b + 4));

                    if( *h == 1U )
                    {
                        if( *p == index )
                        {
                            return observe_t::result_t::emRET_SUCCESS;
                        } else {
                            return observe_t::result_t::emRET_FRAME;
                        }
                    } else {
                        return observe_t::result_t::emRET_WAITTING;
                    }
                };

                // 发起请求
                auto err = observe.request( buffer, on_reply, emTIMEOUT );

                static const char* txt[] =
                {
                    "emRET_SUCCESS",
                    "emRET_SEND",
                    "emRET_REQUEST",
                    "emRET_FRAME",
                    "emRET_FINISH",
                    "emRET_WAITTING",
                    "emRET_PROCESSED",
                    "emRET_UNKNOWN",
                    "emRET_TIMEOUT",
                    "emRET_CANCEL"
                };

                if( err == observe_t::result_t::emRET_SUCCESS )
                {
                    log_inf( "sync request %u OK", index );
                    ret += 1;
                } else {
                    log_err( "sync request %u result: %s", index, txt[(int)err] );
                    to += 1;
                }
            };

            // 测试数据的模板
            byte_t content[] = { 0xaa, 0xbb, 0xcc, 0x01, 0U, 0U, 0U, 0U, 0x12, 0x34 };

            // 重复发起同步请求
            {
                for( uint32_t i = 0; i < emCOUNT; ++i )
                {
                    log_inf( "push a packet: %u", i );

                    auto* p = (uint32_t*)(content + 4);
                    *p = i;

                    request( i, loop, parses_t::buffer_t{ content, content + sizeof( content ) } );

                    if( emINTERVAL ) std::this_thread::sleep_for( std::chrono::milliseconds( emINTERVAL ) );
                }
            }

            // 测试结束清理工作
            {
                while( (to + ret) != emCOUNT ) std::this_thread::sleep_for( std::chrono::milliseconds( 100U ) );

                std::this_thread::sleep_for( std::chrono::milliseconds( 100U ) );

                loop.parses_.cannel();

                th_.join();

                log_nte( "=======================================================================" );

                if( to )
                {
                    log_war( "timeout count: %u / %u", to, emCOUNT );
                }

                if( ret < emCOUNT )
                {
                    log_war( "process count not full: %u / %u", ret, emCOUNT );
                }

                if( dop != emCOUNT * 2 )
                {
                    log_err( "drop bytes count error: %u / %u", dop, emCOUNT * 2 );
                }
            }

            return ( ( to + ret ) == emCOUNT ) && dop == emCOUNT * 2;
        }
    };

    TEST_CASE_ADD( "parses", case_parses_t, false );

} // namespace test

#endif // __case_parses_kenny_kfjiweur89u83r33e3e__

